package My

import (
	"errors"
	"fmt"
	"db2s/ETL"
	"db2s/global"
	"db2s/outPut"
	"reflect"
	"runtime"
	"strings"
	"time"
)

type RowsActive struct {
}

func (my RowsActive) WriteInsert(s global.RowsActiveInput) (any, error) {
	var (
		event = "[WriteInsert]"
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	beginTime := time.Now()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v  Start writing repair statements of table %v.%v to the repair file.", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table)
	WLog.Debug(vlog)
	WriteTextI := outPut.FileOut("text", map[string]any{"fileN": s.Optimizer.FilePoint, "logSeq": s.LogSeq,
		"bufSize": 1024 * 1024 * 4, "sqlType": "sql", "rowsS": "\n",
	})
	if !WriteTextI.AppendWrite("", s.ApplySqlGather) {
		err := errors.New(fmt.Sprintf("datafix sql write fail"))
		vlog = fmt.Sprintf("(%d) %v %v datafix sql write fail. error is {%v}", s.LogSeq, callFuncInfo, event, err)
		WLog.Error(vlog)
		return nil, err
	}
	timeOut := time.Since(beginTime).Milliseconds()
	vlog = fmt.Sprintf("(%d) %v %v Write the repair statement of table %v.%v to the repair file successfully. exec timeOut is {%v}", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table, timeOut)
	WLog.Debug(vlog)
	return timeOut, nil
}

// ExecInsert 应用插入sql语句
func (my RowsActive) ExecInsert(s global.RowsActiveInput) (any, error) {
	var (
		setVariables = []string{"SET session unique_checks=0", "SET session foreign_key_checks=0"}
		event        = "[ApplyInsert]"
		execTimeout  int64
		shardName    string
		err          error
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	shardName = "single"
	vlog = fmt.Sprintf("(%d) %v %v Table %v.%v starts executing the insert repair statement", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table)
	WLog.Debug(vlog)
	if len(shardName) == 0 {
		WLog.Warn(fmt.Sprintf("(%d) %v %v The execution of a sql statement failed! table is %v.%v. error is {ShardName is entry}", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table))
		switch fmt.Sprintf("%v", reflect.TypeOf(s.ApplySqlGather)) {
		case "*string":
			runtime.SetFinalizer(s.ApplySqlGather.(*string), nil)
		case "[]*string":
			for _, v := range s.ApplySqlGather.([]*string) {
				runtime.SetFinalizer(v, nil)
			}
		case "[][]*string":
			for _, v := range s.ApplySqlGather.([][]*string) {
				for _, k := range v {
					runtime.SetFinalizer(k, nil)
				}
			}
		}
		return nil, errors.New(fmt.Sprintf("%v", "ShardName is entry"))
	}
	active := ETL.InstanceActiveS{SessionSet: setVariables, LobSwitch: s.TableInfo.LobSwitch, DB: s.DB[shardName], StopTime: s.SqlExecStopTime, SqlMode: s.Optimizer.SqlMode, SqlLogBin: s.Optimizer.SqlLogBin, InsertPreFix: s.SqlPrefix}
	if execTimeout, err = active.TrxInsert(s.ApplySqlGather); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. table is %v.%v,error is {%v}", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table, err)
		WLog.Error(vlog)
		return nil, err
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. table is %v.%v, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table, execTimeout)
	WLog.Debug(vlog)
	return execTimeout, err
}
func (my RowsActive) WriteDelete(s global.RowsActiveInput) (any, error) {
	var (
		event = "[WriteDelete]"
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	beginTime := time.Now()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v  Start writing repair statements of table %v.%v to the repair file.", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table)
	WLog.Debug(vlog)
	WriteTextI := outPut.FileOut("text", map[string]any{"fileN": s.Optimizer.FilePoint, "logSeq": s.LogSeq,
		"bufSize": 1024 * 1024 * 4, "sqlType": "sql", "rowsS": "\n",
	})
	if !WriteTextI.AppendWrite("", s.ApplySqlGather) {
		err := errors.New(fmt.Sprintf("datafix sql write fail"))
		vlog = fmt.Sprintf("(%d) %v %v datafix sql write fail. error is {%v}", s.LogSeq, callFuncInfo, event, err)
		WLog.Error(vlog)
		return nil, err
	}
	timeOut := time.Since(beginTime).Milliseconds()
	vlog = fmt.Sprintf("(%d) %v %v Write the repair statement of table %v.%v to the repair file successfully. exec timeOut is {%v}", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table, timeOut)
	WLog.Debug(vlog)
	return timeOut, nil
}

// ExecDelete 应用插入sql语句
func (my RowsActive) ExecDelete(s global.RowsActiveInput) (any, error) {
	var (
		setVariables = []string{"SET session unique_checks=0", "SET session foreign_key_checks=0"}
		event        = "[ApplyDelete]"
		execTimeout  int64
		shardName    string
		err          error
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	shardName = "single"
	vlog = fmt.Sprintf("(%d) %v %v Table %v.%v starts executing the delete repair statement", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table)
	WLog.Debug(vlog)
	active := ETL.InstanceActiveS{SessionSet: setVariables, LobSwitch: s.TableInfo.LobSwitch, DB: s.DB[shardName], StopTime: s.SqlExecStopTime, SqlMode: s.Optimizer.SqlMode, SqlLogBin: s.Optimizer.SqlLogBin}
	if execTimeout, err = active.TrxInsert(s.ApplySqlGather); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. table is %v.%v,error is {%v}", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table, err)
		WLog.Error(vlog)
		return nil, err
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. table is %v.%v, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, s.TableInfo.Schema, s.TableInfo.Table, execTimeout)
	WLog.Debug(vlog)
	return execTimeout, nil
}

// Insert 应用插入sql语句
func (my RowsActive) Insert(s global.RowsActiveInput) (any, error) {
	if strings.EqualFold(s.Optimizer.Active, "file") {
		return my.WriteInsert(s)
	} else if strings.EqualFold(s.Optimizer.Active, "table") {
		return my.ExecInsert(s)
	} else {
		return nil, nil
	}
}

// Delete 应用插入sql语句
func (my RowsActive) Delete(s global.RowsActiveInput) (any, error) {
	if strings.EqualFold(s.Optimizer.Active, "file") {
		return my.WriteDelete(s)
	} else if strings.EqualFold(s.Optimizer.Active, "table") {
		return my.ExecDelete(s)
	} else {
		return nil, nil
	}
}
